iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0

大綱

  • TextInputLayout
    • Simple Using
    • Adding a leading icon
    • Leading icon attributes
    • Adding a trailing icon
      • Password toggle
      • Clear text
      • Custom icon
    • Adding helper text
    • **Adding counter **
    • Adding errors
    • Helper/error/counter text attributes
    • Adding a prefix/suffix
    • Dropdown menu
  • TextInputEditText
    • Input Type
    • Input text attributes
  • Filled text field
    • Anatomy
    • Container attributes
    • Label attributes
    • Activation indicator attributes
    • Styles
  • Outlined text field
    • Anatomy
    • Container attributes
    • Label attributes
    • Styles
  • Custom Style

TextInputLayout

作為 Text fields 最核心的元件,Material Design 將它拆分為 TextInputlayout 與 TextInputEditText。而 TextInputLayout 是 LinearLayout 的子類,作為一個 ViewGroup,它的角色是用來裝飾 Text fields 的 Hint、icon、background 等等,任何想要對 Text fields 的設計與修改,都會在 TextInputLayout 上去設置

Simple Using

那最簡單的設置,就是將 TextInputLayout 裡面包裹一個 TextInputEditText
https://ithelp.ithome.com.tw/upload/images/20220920/20151680s8IMTs0Cyc.jpg

<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/textField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/label">

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
    />

</com.google.android.material.textfield.TextInputLayout>

Adding a leading icon

若想要在 start 位置放置 icon 就只要添加下面程式碼
https://ithelp.ithome.com.tw/upload/images/20220920/20151680gCaAtpvHrj.png

<com.google.android.material.textfield.TextInputLayout
    ...
    app:startIconDrawable="@drawable/ic_favorite_24dp"
    ...
</com.google.android.material.textfield.TextInputLayout>

Leading icon attributes

https://ithelp.ithome.com.tw/upload/images/20220920/20151680IRbB9JN2Z1.png

Adding a trailing icon

若想要在 start 位置放置 icon 就只要添加下面程式碼,而 Material Design 已經提供幾個 mode 使用

Password toggle

在登入或輸入比較敏感性資料的畫面,通常都會希望隱藏輸入的資料,就能使用 password toggle
https://ithelp.ithome.com.tw/upload/images/20220920/201516807my9j7b6iu.png

<com.google.android.material.textfield.TextInputLayout
    ...
    app:endIconMode="password_toggle">
    ...
</com.google.android.material.textfield.TextInputLayout>

Clear text

在輸入的狀態下,點擊 clear text icon 能一次清除所有的資料
https://ithelp.ithome.com.tw/upload/images/20220920/20151680jzGx4guCgM.png

<com.google.android.material.textfield.TextInputLayout
    ...
    app:endIconMode="clear_text">
    ...
</com.google.android.material.textfield.TextInputLayout>

Custom icon

若上述的情況都不滿足,也有自定義的選項,但要先將 mode 設置為 custom,才能去設置 icon drawable,否則直接設置的話會失效

  • in layout
<com.google.android.material.textfield.TextInputLayout
    ...
    app:endIconMode="custom"
    app:endIconDrawable="@drawable/ic_check_circle_24dp"
    ...
</com.google.android.material.textfield.TextInputLayout>
  • in code
    使用自定義的 icon,那它的 action 也能讓我們自行設置
textField.setEndIconOnClickListener {
  // Respond to end icon presses
}

Adding helper text

<com.google.android.material.textfield.TextInputLayout
    ...
    app:helperTextEnabled="true"
    app:helperText="@string/helper_text">
    ...

</com.google.android.material.textfield.TextInputLayout>

https://ithelp.ithome.com.tw/upload/images/20220920/20151680COMJId78rS.png

Adding counter

maxLength 這個屬性只是單純提示用戶應該輸入的字數,不會真的讓用戶只能輸入此上限。若是超過則會變為 error 的狀態提示用戶已經超出上限,若是真的想要在應用上去限制,應該在 TextInputEditText 設置 maxLength

<com.google.android.material.textfield.TextInputLayout
    ...
    app:counterEnabled="true"
    app:counterMaxLength="20">
    ...
</com.google.android.material.textfield.TextInputLayout>

https://ithelp.ithome.com.tw/upload/images/20220920/20151680D5G2gi9fS2.png

Adding errors

errors 在官方的介紹上有點簡略,這邊我用自己的範例來跟大家解釋一下。假如今天我們有設置 counter、helper text、endIcon,那這些屬性會被影響嗎? 並不會,當超出限制到 errors 狀態時,雖然會更換 helper text 與 endIcon,但在限制內時又會變換回來。有興趣的可以試著 Demo 看看

https://ithelp.ithome.com.tw/upload/images/20220920/20151680IZetbaX2ni.jpg

  • in layout
<com.google.android.material.textfield.TextInputLayout
                android:hint="Error Text Demo"
                app:helperText="Test error override"
                app:endIconMode="clear_text"
                app:counterEnabled="true"
                app:counterMaxLength="20"
                app:errorEnabled="true">
</com.google.android.material.textfield.TextInputLayout>
  • in code
 binding.textErrorTextField.addTextChangedListener {
         if (binding.textErrorTextField.text.toString().length > 20)
             binding.textErrorTextFieldLayout.error = "exceed the length limit "
         else
             binding.textErrorTextFieldLayout.error = null
}

Helper/error/counter text attributes

https://ithelp.ithome.com.tw/upload/images/20220920/20151680wE7f8jZPID.png

Adding a prefix/suffix

<com.google.android.material.textfield.TextInputLayout
    ...
    app:prefixText="@string/prefix"
    app:suffixText="@string/suffix">
    ...
</com.google.android.material.textfield.TextInputLayout>

https://ithelp.ithome.com.tw/upload/images/20220920/20151680n276OyvCvJ.png

Dropdown menu

InputLayout 不僅僅是能改變上述的外觀屬性,還能變成類似 Spinner 的樣式。只不過在設置上,與一般的 Text fields 有點不同,裡面包裹的元件必須是 AutoCompleteTextView。因為功能上我們並不需要編輯與輸入,要的是展開選取的功能,所以在 InputType 的地方會改成 none 的形式,以免讓用戶能編輯修改

https://ithelp.ithome.com.tw/upload/images/20220920/20151680Yxx5QxFDzS.png

  • in layout
<com.google.android.material.textfield.TextInputLayout
    ...
    style="@style/Widget.MaterialComponents.TextInputLayout.*.ExposedDropdownMenu">

    <AutoCompleteTextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="none"
    />
</com.google.android.material.textfield.TextInputLayout>
  • in code
val dropMenuList = listOf("Material", "Design", "Components", "Android")
val menuAdapter = ArrayAdapter(requireContext(), R.layout.itemview_dropmenu_item, dropMenuList)
    binding.dropDownAutoText.setAdapter(menuAdapter)
  • In the item layout (itemview_dropmenu_item.xml)
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:maxLines="1"
    android:padding="16dp"
    android:textAppearance="?attr/textAppearanceSubtitle1"
    android:textColor="@color/white" />

TextInputEditText

上面已經提到 Material Design 把 text fields 分為兩個部分,TextInputEditText 就是作為讓用戶輸入編輯的角色。但要注意的是,使用上與 EditText 是相同的,因為已經把外觀的部分都交給 TextInputLayout 了,所以在設置 hint 的時候,必須在 Inputlayout 而不是 InputEditText

Input Type

而作為輸入的元件,Material Design 已經貼心的提供多種輸入型態給我們使用。例如,上面提到過的 InputType none 就能讓用戶無法進行輸入,或是限定只能輸入數字或文字等等

 <com.google.android.material.textfield.TextInputEditText
                    android:inputType="number"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />

Input text attributes

https://ithelp.ithome.com.tw/upload/images/20220920/20151680bxkvZ9iSLQ.png


Filled text field

在預設情況下,text field 就會是 Filled,不需要在額外設置 Style
https://ithelp.ithome.com.tw/upload/images/20220920/20151680M1FGMIKsv6.png

<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/filledTextField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/label">

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
    />

</com.google.android.material.textfield.TextInputLayout>

Anatomy

https://ithelp.ithome.com.tw/upload/images/20220920/20151680p3VVcDDMRa.png

  1. Container
  2. Leading icon
  3. Label
  4. Input text
  5. Trailing icon
  6. Activation indicator ( Filled text 獨有的 )
  7. Helper/error/counter text
  8. Prefix/suffix/placeholder ( 礙於篇幅,所以沒有出現 )

Container attributes

https://ithelp.ithome.com.tw/upload/images/20220920/20151680fiMqlLknAg.png

Label attributes

  • hintAnimationEnabled 若將此屬性設為 false,能關閉 hint 移動的動畫
  • expandedHintEnabled 若將此屬性設為 false,則 hint 就會一直停在 textInputEditText 上方
    https://ithelp.ithome.com.tw/upload/images/20220920/20151680tSzyju1O5q.png

Activation indicator attributes

位於 Filled text baseline 的位置,會在 Focused 的時候變色顯示,讓用戶知道目前正在此輸入框進行操作。所以在屬性上,分別有 Focused Width、Width 兩種寬度屬性可設置,是為了透過之間的變化產生動畫效果。如果想要自定義修改這些屬性,記得 Focused Width 要大於 Width
https://ithelp.ithome.com.tw/upload/images/20220920/20151680iUBacx30Gw.png

Styles

https://ithelp.ithome.com.tw/upload/images/20220920/20151680yAIdBzOkdP.png

Outlined text field

透過設置 Style 就能更換
https://ithelp.ithome.com.tw/upload/images/20220920/20151680vaxSTUp1JN.png

<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/outlinedTextField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/label"
    style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
    />

</com.google.android.material.textfield.TextInputLayout>

Anatomy

https://ithelp.ithome.com.tw/upload/images/20220920/20151680W2Ru8LJVap.png

  1. Container
  2. Leading icon
  3. Label
  4. Input text
  5. Trailing icon
  6. Helper/error/counter text
  7. Prefix/suffix/placeholder ( 礙於篇幅 沒有顯示 )

Container attributes

Outlined text 在 Container 的屬性相對 Filled text 較多了一些,大多是關於 Stroke (框線),也是它最大的特色,是將 indicator 交給 Stroke 的變化去提示用戶目前正在 Focused。而它也有FocusedWidth 與 Width,與剛剛提到的 Activation indicator 是相同概念,在自定義數值時,一樣要讓 Focused 大於 Not Focused

https://ithelp.ithome.com.tw/upload/images/20220920/20151680GA5E04QPqd.png

Label attributes

下圖,官方的屬性列表沒有提到 Filled Text 關於 Hint 動畫的設置,不代表真的沒有。因為我們切換這兩種型態的 text fields 只是改變 style,並不是真的換了一個元件。所以還是可以去設置的,只不過官方這樣的列表,應該是不希望我們在 Outlined text 中去改動 Hint 的動畫與設置

https://ithelp.ithome.com.tw/upload/images/20220920/20151680gxpKMXuMfb.png

Styles

https://ithelp.ithome.com.tw/upload/images/20220920/20151680Nwk8nt3wMz.png


Custom Style

如果上述這幾個種類的 Text fields 在 Material Design 上的設置剛好不符合我們要的,就可以依照剛剛所介紹的過 attributes 去做修改。這邊就用我自己魔改的範例,當中我自定義了 Outlined text、dropdownMenu 的配色與字型大小等等。Text fields 組成顏色都是對應 ColorSurface、ColorOnSurface 與 ColorPrimary,想魔改的各位可以從這幾個屬性下手

<style name="Widget.App.OutlinedBox.DropDownMenu" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense.ExposedDropdownMenu">
        <item name="materialThemeOverlay">@style/ThemeOverlay.App.ToggleButton</item>
    </style>

    <style name="ThemeOverlay.App.OutlinedBox.DropDownMenu" parent="">
        <item name="colorOnSurface">@color/white</item>
        <item name="colorSurface">@color/lightYellow</item>
    </style>

    <style name="Widget.App.TextInputLayout.OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
        <item name="materialThemeOverlay">@style/ThemeOverlay.App.TextInputLayout.OutlinedBox</item>
        <item name="shapeAppearance">@style/ShapeAppearance.App.SmallComponent</item>
        <item name="hintTextColor">@color/white</item>
    </style>

    <style name="ThemeOverlay.App.TextInputLayout.OutlinedBox" parent="">
        <item name="colorPrimary">@color/lightYellow</item>
        <item name="colorOnSurface">@android:color/holo_green_light</item>
        <item name="colorError">@color/red</item>
        <item name="textAppearanceSubtitle1">@style/TextAppearance.App.Subtitle1</item>
        <item name="textAppearanceCaption">@style/TextAppearance.App.Caption</item>
        <item name="editTextStyle">@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox
        </item>
    </style>

小結

Text fields 在實作上不會特別困難,很多小東西 Material Design 已經幫我們做好,若是你還在用最原始的 EditText 想設計出好看好用的 InputText 畫面,建議可以直接使用 Text fields,絕對能滿足在 UI 設計上大部分的需求。若是因為版本問題無法引進也沒關係,至少要效仿將其分為 InputLayout 與 InputEditText 的概念,切分元件之間的層級與職責,才是 Material Design 最值得我們學習的地方 /images/emoticon/emoticon33.gif

若是對實作還是有點不懂的,這邊提供我的 Github 方便大家參考


上一篇
Day 4 - Text fields ( Design )
下一篇
Day 6 - App bar : Top ( Design )
系列文
從 Google Material Design Components 來了解與實作 Android 的 UI/UX 元件設計30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言